﻿#include "OiPCH.hpp"
#include "View/OiDefinitionTemplDlg.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        ListItemLabel::ListItemLabel(QWidget* parent/* = NULL*/) : QLabel(parent)
        {
            setWordWrap(true);
            auto f = font();
            f.setPointSize(14);
            setFont(f);
            setStyleSheet("background:rgba(165, 165, 165, 100)");
            setAlignment(Qt::AlignCenter);
            setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        }

        void ListItemLabel::setDispText(const QString& t)
        {
            _text = t;
            setText(t);
        }

        void ListItemLabel::setSelectText(const QString& st)
        {
            int matchS, matchL;

            if(containsText(st, &matchS, &matchL))
            {
                auto len = _text.length();
                setText(QString("%1<span style=\"background:#ffff00;\"><b>%2</b></span>%3").arg(_text.left(matchS)).arg(_text.mid(matchS, matchL)).arg(_text.right(len - matchS - matchL)));
            }
            else
            {
                setText(_text);
            }
        }

        bool ListItemLabel::containsText(const QString& t, int* start, int* lenth)
        {

            QList<int> ss;
            QList<int> ls;
            QList<int> ts;
            QChar btc;
            int bti = -1;

            for(int ti = 0; ti < t.size(); bti++)
            {
                if(t[ti] != '_' && t[ti] != '-' && t[ti] != ',' && t[ti] != ' ')
                {
                    bti = ti;
                    btc = t[ti];
                    break;
                }
            }

            if(bti < 0)
            {
                if(start) *start = 0;
                if(lenth) *lenth = 0;
                return true;
            }

            for(int si = 0; si < _text.size(); si++)
            {
                if(_text[si] == '_' || _text[si] == '-' || _text[si] == ',' || _text[si] == ' ')
                {
                    for(int & lsi : ls)
                    {
                        lsi++;
                    }
                    continue;
                }

                for(int tsi = 0; tsi < ts.size(); tsi++)
                {
                    int& ti = ts[tsi];

                    do
                    {
                        ti++;
                    } while(ti < t.size() && ( t[ti] == '_' || t[ti] == '-' || t[ti] == ',' || t[ti] == ' ' ));

                    if(ti < t.size())
                    {
                        if(_text[si] == t[ti])
                        {
                            ls[tsi]++;
                        }
                        else
                        {
                            ss.removeAt(tsi);
                            ls.removeAt(tsi);
                            ts.removeAt(tsi);

                            tsi--;

                            continue;
                        }
                    }

                    if(ti >= t.size() - 1)
                    {
                        if(start) *start = ss[tsi];
                        if(lenth) *lenth = ls[tsi];
                        return true;
                    }
                }

                if(_text[si] == btc)
                {
                    ss.push_back(si);
                    ls.push_back(1);
                    ts.push_back(0);
                }
            }

            return false;
        }

        class ProductDlgImpl : public Impl<ProductDlg>
        {
        public:
            void init(ProductMeasurePage type);

            void update();

            void addItem(QString name);

            void setCurrent(QString name);

        public:
            QLineEdit* _searchName;
            QPushButton* _clearSearch;

            QListWidget* _formulaList;

            QPushButton* _importButton;
            QPushButton* _appendButton;
            QPushButton* _modifyButton;
            QPushButton* _deleteButton;

            QPushButton* _completeButton;
            QPushButton* _cancelButton;

            ProductWidget* _productViewer;

        public:
            QMap<QString, QListWidgetItem*> _items;
            QString _currentProduct;
            int _operator;
        };

        void ProductDlgImpl::init(ProductMeasurePage type)
        {
            OI_Q(ProductDlg);

            q->setWindowTitle(ProductDlg::tr("规格管理器"));

            auto font = q->font();
            font.setPixelSize(25);

            QHBoxLayout* formulaLayout = new QHBoxLayout(q);
            formulaLayout->setContentsMargins(2, 0, 2, 0);
            formulaLayout->setSpacing(2);
            
            auto listWidget = new QWidget();
            listWidget->setMinimumWidth(200);
            QVBoxLayout* formulaListLayout = new QVBoxLayout(listWidget);
            formulaListLayout->setContentsMargins(0, 0, 0, 0);
            formulaListLayout->setSpacing(2);
 
            QHBoxLayout* searchNameLayout = new QHBoxLayout();
            searchNameLayout->setContentsMargins(0, 0, 0, 0);
            searchNameLayout->setSpacing(2);
            _searchName = new QLineEdit();
            _searchName->setObjectName("_searchName");
            _searchName->setPlaceholderText(ProductDlg::tr("产品搜索关键字"));
            _searchName->setFont(font);

            _clearSearch = new QPushButton(ProductDlg::tr("清空"));
            _clearSearch->setObjectName("_clearSearch");
            _clearSearch->setFont(font);
            searchNameLayout->addWidget(_searchName, 1);
            searchNameLayout->addWidget(_clearSearch);

            _formulaList = new QListWidget();
            _formulaList->setObjectName("_formulaList");
            _formulaList->setGridSize(QSize(260, 55));
            _formulaList->setResizeMode(QListView::Adjust);
            _formulaList->setDragDropMode(QListWidget::NoDragDrop);
            _formulaList->setSelectionMode(QListWidget::SingleSelection);
            _formulaList->setMovement(QListView::Static);
            _formulaList->setViewMode(QListWidget::ListMode);
            _formulaList->setSpacing(5);
            _formulaList->setContextMenuPolicy(Qt::CustomContextMenu);
            _formulaList->setFrameShape(QFrame::NoFrame);

            auto buttonsWidget = new QWidget();
            QHBoxLayout* formulaButtonLayout = new QHBoxLayout(buttonsWidget);
            formulaButtonLayout->setContentsMargins(0, 0, 0, 0);
            formulaButtonLayout->setSpacing(2);
                    
            _importButton = new QPushButton(q);
            _importButton->setObjectName("_importButton");
            _importButton->setText(ProductDlg::tr("导入"));
            _importButton->setFont(font);
            _appendButton = new QPushButton(q);
            _appendButton->setObjectName("_appendButton");
            _appendButton->setText(ProductDlg::tr("添加"));
            _appendButton->setFont(font);
            _modifyButton = new QPushButton(q);
            _modifyButton->setObjectName("_modifyButton");
            _modifyButton->setText(ProductDlg::tr("修改"));
            _modifyButton->setFont(font);
            _deleteButton = new QPushButton(q);
            _deleteButton->setText(ProductDlg::tr("删除"));
            _deleteButton->setObjectName("_deleteButton");
            _deleteButton->setFont(font);
            _completeButton = new QPushButton(q);
            _completeButton->setText(ProductDlg::tr("保存"));
            _completeButton->setObjectName("_completeButton");
            _completeButton->setFont(font);
            _cancelButton = new QPushButton(q);
            _cancelButton->setText(ProductDlg::tr("取消"));
            _cancelButton->setObjectName("_cancelButton");
            _cancelButton->setFont(font);
            formulaButtonLayout->addWidget(_importButton);
            formulaButtonLayout->addWidget(_appendButton);
            formulaButtonLayout->addWidget(_modifyButton);
            formulaButtonLayout->addWidget(_deleteButton);
            formulaButtonLayout->addWidget(_completeButton);
            formulaButtonLayout->addWidget(_cancelButton);

            formulaListLayout->addLayout(searchNameLayout);
            formulaListLayout->addWidget(_formulaList, 1);
            formulaListLayout->addWidget(buttonsWidget);

            _productViewer = new ProductWidget(type, q);

            formulaLayout->addWidget(_productViewer, 1);
            formulaLayout->addWidget(listWidget);

            _completeButton->hide();
            _cancelButton->hide();

#ifdef NDEBUG
            bool admin0 = (UserManage::instance()->permission() & PT_AddDelFormular);
            bool admin1 = (UserManage::instance()->permission() & PT_ModifyFormular);
            _importButton->setEnabled(admin0);
            _appendButton->setEnabled(admin0);
            _modifyButton->setEnabled(admin1);
            _deleteButton->setEnabled(admin0);
#endif

            _operator = 0;

            update();

            QMetaObject::connectSlotsByName(q);
        }

        void ProductDlgImpl::update()
        {
            _items.clear();

            _formulaList->blockSignals(true);
            _formulaList->clear();
            _formulaList->blockSignals(false);

            QDir dir(PLScanner::instance()->productDir);

            for (auto info : dir.entryInfoList(QStringList() << "*.plsp", QDir::Files))
            {
                addItem(info.fileName().remove(".plsp"));
            }
            
            setCurrent(_currentProduct);
        }

        void ProductDlgImpl::addItem(QString name)
        {
            _formulaList->blockSignals(true);

            QListWidgetItem* item = new QListWidgetItem(_formulaList);
            item->setFlags(Qt::ItemIsTristate | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
            item->setData(Qt::UserRole + 1, name);
            item->setSizeHint(QSize(250, 50));
            ListItemLabel* label = new ListItemLabel();
            label->setDispText(name);
            _formulaList->setItemWidget(item, label);

            _formulaList->blockSignals(false);

            _items[name] = item;
        }

        void ProductDlgImpl::setCurrent(QString name)
        {
            _formulaList->blockSignals(true);

            _currentProduct = name;

            if (name.isEmpty() ||
                !_items.contains(name))
            {
                _formulaList->setCurrentRow(-1);
                ProductParams params;
                params.showType = 1;
                _productViewer->setParams(name, params);
            }
            else
            {
                _formulaList->setCurrentItem(_items[name]);
                ProductParams params;
                ProductParams tmpParams;
                if (ProductParams::loadFromLocal(params, name))
                {
                    tmpParams = params;
                    tmpParams.showType = 1;
                   /* for (int i = 0 ; i < params.profiles.size();i++)
                    {
                        for (int j = 0; j < params.profiles[i].size(); j++)
                        {
                            tmpParams.profiles[i][j].setY(params.profiles[i][j].y() / PLScanner::instance()->scaleView);
                        }                      
                    }
                    tmpParams.materialsThickness /= PLScanner::instance()->scaleView;
                    for (int i = 0 ; i < tmpParams.measureThickness.size();i++)
                    {
                        tmpParams.measureThickness[i].setY(tmpParams.measureThickness[i].y() / PLScanner::instance()->scaleView);
                    }
                    for (int i = 0; i < tmpParams.definitionPoints.size(); i++)
                    {
                        tmpParams.definitionPoints[i].thicknessLeft /= PLScanner::instance()->scaleView;
                        tmpParams.definitionPoints[i].thicknessRight /= PLScanner::instance()->scaleView;
                    }*/

                    _productViewer->setParams(name, tmpParams);
                }
                else
                {
                    OiAlerter() << ProductDlg::tr("参数加载失败!");
                }
            }

            _formulaList->blockSignals(false);

        }

        ProductDlg::ProductDlg(ProductMeasurePage type, QWidget* parent/* = NULL*/)
            : Ctrl::Dialog(parent)
        {
            OI_I(ProductDlg)->init(type);
        }

        void ProductDlg::updatePage()
        {
            OI_IMPL()->update();
        }

        void ProductDlg::setCurrent(QString name)
        {
            OI_IMPL()->setCurrent(name);
        }

        void ProductDlg::closeEvent(QCloseEvent *e)
        {
            OI_F(ProductDlg);
        }

        void ProductDlg::on__searchName_textChanged(const QString &name)
        {
            OI_F(ProductDlg);

            auto rows = d->_formulaList->count();

            for(auto i = 0; i < rows; i++)
            {
                auto item = d->_formulaList->item(i);
                auto label = reinterpret_cast<ListItemLabel*>( d->_formulaList->itemWidget(item) );
                if(label->containsText(name))
                {
                    item->setHidden(false);
                    label->setSelectText(name);
                }
                else
                {
                    item->setHidden(true);
                }
            }
        }

        void ProductDlg::on__clearSearch_clicked()
        {
            OI_F(ProductDlg);

            d->_searchName->setText(QString(""));
        }

        void ProductDlg::on__formulaList_currentRowChanged(int row)
        {
            OI_F(ProductDlg);

            if (row >= 0)
            {
                d->setCurrent(d->_formulaList->item(row)->data(Qt::UserRole + 1).toString());
            }
            else
            {
                d->setCurrent("");
            }
        }

        void ProductDlg::on__formulaList_itemDoubleClicked(QListWidgetItem* item)
        {
            OI_F(ProductDlg);

            auto newName = item->data(Qt::UserRole + 1).toString();

            if (newName == ProductParams::current())
            {
                OiAlerter() << tr("与当前配方一致，无法切换");
                return;
            }
         
            if (QMessageBox::Yes == QMessageBox::information(this, tr("提示"), tr("是否切换至配方%1？").arg(newName), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
            {
                ProductParams::setNext(newName);
                close();
            }
        }

        void ProductDlg::on__importButton_clicked()
        {
            auto file = QFileDialog::getOpenFileName(this, tr("加载配方"), tr("配方信息.xlsx"), tr("excel文件 (*.xlsx)"));
            if (!file.isEmpty())
            {
                QXlsx::Document* xlsx = new QXlsx::Document(file);
                QXlsx::CellRange range = xlsx->dimension();
                int cols = range.lastColumn();
                int rows = range.lastRow();

                OiDebug() << "尝试导入" << rows << "行数据";

                ProductParams params;
                params.materialsType = 1;
                params.materialsWidth = 0;
                params.materialsThickness = 0;
                params.measureType = 0;
                params.showType = 1;
                params.templMsrFlag = true;

                int validCount = 0;
                for (int row = 2; row <= rows; row++)
                {
                    int type = xlsx->read(row, 2).toInt();
                    bool isValidParameter;
                    if (type == 0 || type == 2 || type == 3)
                    {
                        xlsx->read(row, 14).toFloat(&isValidParameter);
                    }
                    else if (type == 1)
                    {
                        xlsx->read(row, 11).toFloat(&isValidParameter);
                    }

                    if (!isValidParameter)
                    {
                        continue;
                    }

                    params.specName = xlsx->read(row, 1).toString();

                    QList<DefinitionPoint> dpArr;
                    DefinitionPoint dp;
                    dp.type = type + 6;
                    float preDistance = 0;
                    for (int col = 3; col < cols; col++)
                    {
                        dp.distance = xlsx->read(row, col).toFloat(&isValidParameter);

                        if (!isValidParameter || dp.distance < 0.01)
                        {
                            break;
                        }

                        if (col > 14 && col % 2 == 1 && dp.type == DT_TempleStandPart)
                        {
                            dp.distance += preDistance;
                            preDistance += xlsx->read(row, col).toFloat(&isValidParameter);
                        }

                        dpArr.append(dp);
                    }
                    params.definitionPoints = dpArr;

                    params.config.clear();
                    if (type == 0)
                    {
                        DefinitionTemplDlg dlg(DT_TempleStandLine);
                        dlg.setParams(params);
                        params = dlg.params();
                    }
                    else if (type == 1)
                    {
                        DefinitionTemplDlg dlg(DT_TempleReveseLie);
                        dlg.setParams(params);
                        params = dlg.params();
                    }
                    else if (type == 2)
                    {
                        DefinitionTemplDlg dlg(DT_TempleStandPart);
                        dlg.setParams(params);
                        params = dlg.params();
                    }
                    else if (type == 3)
                    {
                        DefinitionTemplDlg dlg(DT_TempleStandArcs);
                        dlg.setParams(params);
                        params = dlg.params();
                    }

                    if (params.config.size() < 10)
                    {
                        params.config.clear();

                        QPointF fullHighLef;
                        QPointF fullHighRig;
                        auto& dfs = params.definitionPoints;
                        auto& keyPtArr = params.profiles[0];
                        DefinitionType tp = DT_Mutational;
                        if (!dfs.isEmpty())
                        {
                            tp = static_cast<DefinitionType>(dfs[0].type);
                        }
                        switch (tp)
                        {
                        case DT_TempleStandLine:
                        case DT_TempleStandLineMark:
                        {
                            if (keyPtArr.size() != 10)
                            {
                                OiWarning() << "Template A data error: " << keyPtArr.size();
                                return;
                            }
                            fullHighLef = keyPtArr[8];
                            fullHighRig = keyPtArr[1];
                            break;
                        }
                        case DT_TempleReveseLie:
                        case DT_TempleReveseLieMark:
                        {
                            if (keyPtArr.size() != 8)
                            {
                                OiWarning() << "Template B data error: " << keyPtArr.size();
                                return;
                            }
                            fullHighLef = keyPtArr[5];
                            fullHighRig = keyPtArr[1];
                            break;
                        }
                        case DT_TempleStandPart:
                        case DT_TempleStandPartMark:
                        {
                            if (keyPtArr.size() < 10)
                            {
                                OiWarning() << "Template B data error: " << keyPtArr.size();
                                return;
                            }
                            fullHighLef = keyPtArr[2];
                            fullHighRig = keyPtArr[keyPtArr.size() - 1];
                            break;
                        }
                        case DT_TempleStandArcs:
                        case DT_TempleStandArcsMark:
                        {
                            if (keyPtArr.size() != 10)
                            {
                                OiWarning() << "Template B data error: " << keyPtArr.size();
                                return;
                            }

                            fullHighLef = keyPtArr[8];
                            fullHighRig = keyPtArr[1];
                            break;
                        }
                        }

                        float fullHeight = std::abs(fullHighRig.x() - fullHighLef.x());

                        if (fullHeight > 50)
                        {
                            params.config["总高Max"] = 4;
                            params.config["总高Min"] = -4;
                        }
                        else
                        {
                            params.config["总高Max"] = 2;
                            params.config["总高Min"] = -2;
                        }

                        params.config["腰高Max"] = 2;
                        params.config["腰高Min"] = -2;
                        params.config["端点宽Max"] = 0.3;
                        params.config["端点宽Min"] = -0.3;
                        params.config["腰宽Max"] = 0.5;
                        params.config["腰宽Min"] = -0.5;
                        params.config["底部宽Max"] = 0.5;
                        params.config["底部宽Min"] = -0.5;
                    }

                    if (!params.config.contains("截面积") || params.config["截面积"] < 1)
                    {
                        float area = 0;
                        std::vector<cv::Point2f> orderlyProfile;
                        if (params.profiles.size() == 2)
                        {
                            for (int i = 0; i < params.profiles[1].size(); i++)
                            {
                                orderlyProfile.push_back(cv::Point2f(params.profiles[1][i].x(), params.profiles[1][i].y()));
                            }
                            area = cv::contourArea(orderlyProfile);
                        }
                        params.config["截面积"] = area;
                        params.config["截面积Max(%)"] = 3;
                        params.config["截面积Min(%)"] = -3;
                    }

                    auto file = PLScanner::instance()->productDir + "/" + params.specName + ".plsp";
                    if (QFileInfo(file).exists())
                    {
                        OiWarning() << "已存在配方" << params.specName;
                        continue;
                    }
                    if (!ProductParams::saveToLocal(params))
                    {
                        OiWarning() << tr("新建产品失败！");
                        continue;
                    }
                    validCount++;
                }
                OiDebug() << "成功导入" << validCount << "行数据";
            }

            OI_IMPL()->update();
        }

        void ProductDlg::on__appendButton_clicked()
        {
            OI_F(ProductDlg);
            d->_operator = 1;
            d->_formulaList->setEnabled(false);
            d->_appendButton->hide();
            d->_modifyButton->hide();
            d->_deleteButton->hide();
            d->_completeButton->show();
            d->_cancelButton->show();

            ProductParams params;

            QString defaultName = ProductDlg::tr("未命名");
            if(ProductParams::checkName(defaultName))
            {
                for(int i = 0; i < 99; i++)
                {
                    auto temp = defaultName + "_" + QString::number(i);
                    if(!ProductParams::checkName(temp))
                    {
                        defaultName = temp;
                        break;
                    }
                }
            }

            d->_productViewer->setParams(defaultName, params);
            d->_productViewer->setEditable(true);
        }

        void ProductDlg::on__modifyButton_clicked()
        {
            OI_F(ProductDlg);

            if (d->_formulaList->currentRow() < 0)
            {
                return;
            }

            d->_operator = 2;

            d->_formulaList->setEnabled(false);
            d->_appendButton->hide();
            d->_modifyButton->hide();
            d->_deleteButton->hide();
            d->_completeButton->show();
            d->_cancelButton->show();

            d->_productViewer->setEditable(true);
        }

        void ProductDlg::on__deleteButton_clicked()
        {
            OI_F(ProductDlg);

            if (!d->_currentProduct.isEmpty())
            {
                if (QMessageBox::Yes == QMessageBox::information(this, tr("提示"), tr("确定删除配方？"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
                {
                    auto file = PLScanner::instance()->productDir + "/" + d->_currentProduct + ".plsp";
                    if (QFileInfo(file).exists())
                    {
                        QFile::remove(file);
                    }

                    d->_currentProduct.clear();

                    d->update();
                }
            }
        }

        void ProductDlg::on__completeButton_clicked()
        {
            OI_F(ProductDlg);

            if (d->_operator == 1)
            {
                auto parm = d->_productViewer->parmas();
                QString name = Ctrl::InputDialog::getText(
                    this,
                    tr("产品名称"),
                    tr("产品名称："),
                    QLineEdit::Normal,
                    parm.specName
                );
                if (!name.isEmpty())
                {
                    parm.specName = name;
                }
                if (!ProductParams::saveToLocal(parm))
                {
                    OiAlerter() << tr("新建产品失败！");
                }
                else
                {
                    d->_currentProduct = d->_productViewer->name();
                }
            }
            else if (d->_operator == 2)
            {
                if (d->_currentProduct == d->_productViewer->name())
                {
                    auto file = PLScanner::instance()->productDir + "/" + d->_currentProduct + ".plsp";
                    if(QFileInfo(file).exists())
                    {
                        QFile::remove(file);
                    }
                }

                if(!ProductParams::saveToLocal(d->_productViewer->parmas()))
                {
                    OiAlerter() << tr("修改产品失败！");
                }
                else if(d->_currentProduct != d->_productViewer->name())
                {
                    auto file = PLScanner::instance()->productDir + "/"+ d->_currentProduct + ".plsp";
                    if(QFileInfo(file).exists())
                    {
                        QFile::remove(file);
                    }

                    d->_currentProduct = d->_productViewer->name();
                }
            }

            d->_formulaList->setEnabled(true);
            d->_appendButton->show();
            d->_modifyButton->show();
            d->_deleteButton->show();
            d->_completeButton->hide();
            d->_cancelButton->hide();

            d->_productViewer->setEditable(false);
            QDir tempDir;
            QString tempFilePath = tempDir.currentPath()+"\\settings\\" + "formual.ini";  // currentPath()方法返回应用程序所在的当前目录；

            QSettings settings(tempFilePath, QSettings::Format::IniFormat);
            settings.setValue(d->_currentProduct + "/ThicknessValue", d->_productViewer->getThicknessValue());
//            Core::OiSettings()->object()->setValue(d->_currentProduct+"/ThicknessValue", d->_productViewer->getThicknessValue());
            d->update();
        }

        void ProductDlg::on__cancelButton_clicked()
        {
            OI_F(ProductDlg);

            d->_formulaList->setEnabled(true);
            d->_appendButton->show();
            d->_modifyButton->show();
            d->_deleteButton->show();
            d->_completeButton->hide();
            d->_cancelButton->hide();

            d->_productViewer->setEditable(false);

            d->update();
        }

    }
}